package com.jappyframework;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

import com.jappyframework.api.WebService;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.Filer;
import com.sun.mirror.apt.Messager;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.Declaration;

public class JappyAnnotationProcessor implements AnnotationProcessor {

	/**
	 * Annotation processing environment.
	 */
	private final AnnotationProcessorEnvironment env;

	public JappyAnnotationProcessor(AnnotationProcessorEnvironment env) {
		this.env = env;
	}

	public void process() {
		try {
			String sourceXmlFilename = env.getOptions().get("source-web-xml");
			String webXmlFileName = env.getOptions().get("target-web-xml");
			String sourcePath = env.getOptions().get("sourcepath");
			Logger.log(env.getOptions().toString());
			if (webXmlFileName == null) {
				env.getMessager().printError("webxmlpath missing");
				return;
			}
			final WebInfModifier webInfModifier = 
				new WebInfModifier(sourceXmlFilename,
									webXmlFileName);
			final Messager messager = env.getMessager();

			AnnotationTypeDeclaration recipeDecl = (AnnotationTypeDeclaration) env
					.getTypeDeclaration(WebService.class.getName());
			Collection<Declaration> recipes = env
					.getDeclarationsAnnotatedWith(recipeDecl);
			for (Declaration decl : recipes) {
				if (!(decl instanceof ClassDeclaration)) {
					messager.printError(decl.getPosition(),
							"Recipe can not be applied to a non-class member");
					// Dont terminate everything, instead process the good guys.
					continue;
				}

				// Safe to cast now.
				ClassDeclaration cDecl = (ClassDeclaration) decl;

				
				// For this instance of class we can proceed further now.
				WebServiceGenerator generator = new WebServiceGenerator(cDecl, env);
				generator.processClass();

				webInfModifier.addRecipe(cDecl);
				
				try {
					generateRecipeJavaFile(cDecl, generator.getSource());
				} catch (IOException o) {
					messager.printError(cDecl.getPosition(), o.getMessage());
				}
				
				webInfModifier.commit();
			}

		} catch (JappyException e) {
			Logger.log(e);
			env.getMessager().printError(e.getMessage());
			return;
		}
	}

	/**
	 * Helper method to generate the .java file corresponding to the servlet.
	 * 
	 * @param classDecl
	 * @param source
	 * @throws IOException
	 */
	private void generateRecipeJavaFile(ClassDeclaration classDecl,
			JavaSource source) throws IOException {
		Filer f = env.getFiler();
		PrintWriter pw = f.createSourceFile(classDecl.getPackage()
				.getQualifiedName()
				+ "." + classDecl.getSimpleName() + "Servlet");
		pw.write(source.getSourceCode());
		pw.flush();
		pw.close();
	}
}
